package vh.sphynx.net;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.CookieHandler;
import java.net.CookieManager;
import java.net.CookiePolicy;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;

import vh.sphynx.net.core.CacheManager;
import vh.sphynx.net.core.MyX059TrustManager;

public class WebConnection {
	
	private ICacheManager cacheManager;
	private ICookieManager cookies;
	private int timeout = 10000; // 10s
	
	/**
	 * @param args
	 * @throws IOException 
	 * @throws MalformedURLException 
	 */
	public static void main(String[] args) throws MalformedURLException, IOException {
		CookieHandler.setDefault(new CookieManager(null, CookiePolicy.ACCEPT_ALL));
		CacheManager cm = new CacheManager("cache", "cache/archive");
		
		cm.setCacheExpiredPeriod(60);
		//cm.addCacheNameResolver(new BugzillaUrlCacheResolver());
		
		WebConnection wc = new WebConnection(cm, null);
		wc.get(new URL("http://code.google.com/p/chromium/issues/detail?id=46406"), "test");
	}
	
	static {
		MyX059TrustManager.installTrustManager();
	}
	
	public WebConnection() {
		
	}
	
	public WebConnection(ICacheManager cacheManager, ICookieManager cookieManager) {
		this.cacheManager = cacheManager;
		this.cookies = cookieManager;
	}
	
	public String resolveURLCacheName(URL query) {
		return cacheManager.resolveCacheName(query);
	}
	
	private HttpURLConnection prepareConnection(URL query) {
		try {
			URLConnection uconn = query.openConnection( );
			if (!(uconn instanceof java.net.HttpURLConnection))
				throw new java.lang.IllegalArgumentException("URL protocol must be HTTP.");
	        final java.net.HttpURLConnection conn = (java.net.HttpURLConnection)uconn;
			 
			conn.setConnectTimeout(timeout);    // 10 sec
			conn.setReadTimeout(timeout);       // 10 sec
			conn.setInstanceFollowRedirects( true );
			conn.setRequestProperty( "User-agent", "spider" );
			conn.setRequestProperty("Connection", "Keep-Alive");
			//conn.setRequestProperty("Cookie", cookies.getCookies(query));
			conn.setUseCaches(false);
			return conn;
		} catch (IOException e) {
			e.printStackTrace();
			return null;
		}
	}
	
	public String get(String queryURL, int expiredTimeMs) throws MalformedURLException, IOException {
		return get(new URL(queryURL), expiredTimeMs);
	}
	
	public String get(String queryURL, String cacheFile,int expiredTimeMs) throws MalformedURLException, IOException {
		return get(new URL(queryURL), cacheFile, expiredTimeMs);
	}
	
	public String get(URL query, int expiredTimeMs) throws IOException {
		String cacheFile = cacheManager.resolveCacheName(query);
		if (cacheManager.isExpired(cacheFile, expiredTimeMs)) {
			cacheManager.archiveCache(query, cacheFile);
			if (!get(query, cacheFile))
				cacheFile = null;
		}
		return cacheFile;
	}
	
	public String get(URL query, String cacheFile, int expiredTimeMs) throws IOException {
		if (cacheFile == null || cacheFile.length() == 0)
			cacheFile = cacheManager.resolveCacheName(query);
		if (cacheManager.isExpired(cacheFile, expiredTimeMs)) {
			cacheManager.archiveCache(query, cacheFile);
			if (!tryGet(query, cacheFile, 3) || false)
				cacheFile = null;
		}
		return cacheFile;
	}
	
	public boolean tryGet(URL query, String cacheFile, int tryTime) throws IOException {
		for(int i = 1; i <= tryTime; i++) {
			if (get(query, cacheFile)) return true;
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		return false;
	}
	
	public boolean get(URL query, String cacheFile) throws IOException {
		HttpURLConnection conn = prepareConnection(query);
		boolean result = conn != null;
		if (result) {
			conn.setRequestMethod("GET");
			conn.connect();
			
			result = conn.getResponseCode() == HttpURLConnection.HTTP_OK; 
			if (result) {
				// store cookie
				/*for (int i = 0; ; i++) {
					String headerName = conn.getHeaderFieldKey(i);
					String headerValue = conn.getHeaderField(i);
					if (headerName == null && headerValue == null)
						break;
					if ("Set-Cookie".equals(headerName))
						cookies.addCookie(query, headerValue);
				}*/
				// store response content
				InputStream istream = conn.getInputStream();
				int byteLeft = conn.getContentLength();
				FileOutputStream ostream = new FileOutputStream(cacheFile);
				try {
					if (byteLeft == -1)
						byteLeft = Integer.MAX_VALUE;
					int buflen = Math.min(byteLeft, Math.max(4096, istream.available()));
					byte buf[] = new byte[buflen];
					while (byteLeft > 0) {
						int byteRead = istream.read(buf);
						if (byteRead > 0) 
							ostream.write(buf, 0, byteRead);
						byteLeft -= byteRead;
						if (byteRead <=0)
							break;
					}
				}
				finally {
					ostream.close();
					istream.close();
					conn.disconnect();
				}
			}
		}
		return result;
	}

	public void response(URL query) {
		
	}

	public void setCacheManager(ICacheManager cacheManager) {
		this.cacheManager = cacheManager;
	}

	public ICacheManager getCacheManager() {
		return cacheManager;
	}

	public void setCookies(ICookieManager cookies) {
		this.cookies = cookies;
	}

	public ICookieManager getCookies() {
		return cookies;
	}

	public int getTimeout() {
		return timeout;
	}

	public void setTimeout(int timeout) {
		this.timeout = timeout;
	}
}
